package com.yike.product.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yike.common.exception.BusinessException;
import com.yike.common.tool.LoginUtil;
import com.yike.common.tool.StringUtil;
import com.yike.product.dto.BarcodeDto;
import com.yike.product.entity.*;
import com.yike.product.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author Sakura
 * @date 2024/11/5
 */
@Slf4j
public class GoodsExcelListener implements ReadListener<BarcodeDto> {
    private static final int BATCH_COUNT = 30;
    private List<BarcodeDto> cacheList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private BarcodeMapper barcodeMapper;
    private GoodsBrandMapper goodsBrandMapper;
    private GoodsCategoryMapper goodsCategoryMapper;
    private GoodsSpecificationMapper goodsSpecificationMapper;
    private GoodsSupplierMapper goodsSupplierMapper;
    private GoodsUnitMapper goodsUnitMapper;

    // 缓存数据库中已有的品牌、分类等信息
    private Map<String, GoodsBrand> brandCache = new HashMap<>();
    private Map<String, GoodsCategory> categoryCache = new HashMap<>();
    private Map<String, GoodsSpecification> specificationCache = new HashMap<>();
    private Map<String, GoodsSupplier> supplierCache = new HashMap<>();
    private Map<String, GoodsUnit> unitCache = new HashMap<>();

    public GoodsExcelListener(BarcodeMapper barcodeMapper, GoodsBrandMapper goodsBrandMapper,
                              GoodsCategoryMapper goodsCategoryMapper, GoodsSpecificationMapper goodsSpecificationMapper,
                              GoodsSupplierMapper goodsSupplierMapper, GoodsUnitMapper goodsUnitMapper) {
        this.barcodeMapper = barcodeMapper;
        this.goodsBrandMapper = goodsBrandMapper;
        this.goodsCategoryMapper = goodsCategoryMapper;
        this.goodsSpecificationMapper = goodsSpecificationMapper;
        this.goodsSupplierMapper = goodsSupplierMapper;
        this.goodsUnitMapper = goodsUnitMapper;
    }

    @Override
    public void invoke(BarcodeDto barcodeDto, AnalysisContext analysisContext) {
        log.debug("解析到一条数据barcode:{}", JSON.toJSONString(barcodeDto));
        cacheList.add(barcodeDto);
        if (cacheList.size() >= BATCH_COUNT) {
            saveData();
            cacheList.clear();  // 只清空列表，不重新创建
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        saveData();
        log.info("所有数据解析完成！");
    }

    public void saveData() {
        log.info("一共{}条数据，开始存储数据库！", cacheList.size());
        if (CollectionUtils.isNotEmpty(cacheList)) {
            List<Barcode> barcodesToInsert = new ArrayList<>(cacheList.size());
            for (BarcodeDto barcodeDto : cacheList) {
                // 需要校验是否存在相同条码，如果存在则抛出异常
                Integer checkNum = barcodeMapper.selectCount(Wrappers.<Barcode>lambdaQuery()
                        .eq(Barcode::getCode, barcodeDto.getCode()));
                if (checkNum > 0) {
                    throw new BusinessException("商品条码已存在：" + barcodeDto.getCode());
                }
                Barcode barcode = new Barcode();
                BeanUtils.copyProperties(barcodeDto, barcode);

                // 使用缓存避免重复查询
                barcode.setBrandId(getOrInsertBrandId(barcodeDto.getBrand()));
                barcode.setCategoryId(getOrInsertCategoryId(barcodeDto.getCategory()));
                barcode.setSpecificationId(getOrInsertSpecificationId(barcodeDto.getSpecification()));
                barcode.setSupplierId(getOrInsertSupplierId(barcodeDto.getSupplier()));
                barcode.setUnitId(getOrInsertUnitId(barcodeDto.getUnit()));

                barcode.setCreateBy(LoginUtil.getUserId());
                barcodesToInsert.add(barcode);
            }
            barcodeMapper.insertBatch(barcodesToInsert);  // 使用批量插入方式
        }
        log.info("存储数据库成功！");
    }

    private Long getOrInsertBrandId(String brandName) {
        if (StringUtil.isBlank(brandName)) return null;
        return brandCache.computeIfAbsent(brandName, name -> {
            GoodsBrand brand = goodsBrandMapper.selectOne(Wrappers.<GoodsBrand>lambdaQuery()
                    .eq(GoodsBrand::getName, name));
            if (brand == null) {
                brand = new GoodsBrand();
                brand.setName(name);
                brand.setCreateBy(LoginUtil.getUserId());
                goodsBrandMapper.insert(brand);
            }
            return brand;
        }).getId();
    }

    private Long getOrInsertCategoryId(String categoryName) {
        if (StringUtil.isBlank(categoryName)) return null;
        return categoryCache.computeIfAbsent(categoryName, name -> {
            GoodsCategory category = goodsCategoryMapper.selectOne(Wrappers.<GoodsCategory>lambdaQuery()
                    .eq(GoodsCategory::getName, name));
            if (category == null) {
                category = new GoodsCategory();
                category.setName(name);
                category.setCreateBy(LoginUtil.getUserId());
                goodsCategoryMapper.insert(category);
            }
            return category;
        }).getId();
    }

    private Long getOrInsertSpecificationId(String specificationName) {
        if (StringUtil.isBlank(specificationName)) return null;
        return specificationCache.computeIfAbsent(specificationName, name -> {
            GoodsSpecification specification = goodsSpecificationMapper.selectOne(Wrappers.<GoodsSpecification>lambdaQuery()
                    .eq(GoodsSpecification::getName, name));
            if (specification == null) {
                specification = new GoodsSpecification();
                specification.setName(name);
                specification.setCreateBy(LoginUtil.getUserId());
                goodsSpecificationMapper.insert(specification);
            }
            return specification;
        }).getId();
    }

    private Long getOrInsertSupplierId(String supplierName) {
        if (StringUtil.isBlank(supplierName)) return null;
        return supplierCache.computeIfAbsent(supplierName, name -> {
            GoodsSupplier supplier = goodsSupplierMapper.selectOne(Wrappers.<GoodsSupplier>lambdaQuery()
                    .eq(GoodsSupplier::getName, name));
            if (supplier == null) {
                supplier = new GoodsSupplier();
                supplier.setName(name);
                supplier.setCreateBy(LoginUtil.getUserId());
                goodsSupplierMapper.insert(supplier);
            }
            return supplier;
        }).getId();
    }

    private Long getOrInsertUnitId(String unitName) {
        if (StringUtil.isBlank(unitName)) return null;
        return unitCache.computeIfAbsent(unitName, name -> {
            GoodsUnit unit = goodsUnitMapper.selectOne(Wrappers.<GoodsUnit>lambdaQuery()
                    .eq(GoodsUnit::getName, name));
            if (unit == null) {
                unit = new GoodsUnit();
                unit.setName(name);
                unit.setCreateBy(LoginUtil.getUserId());
                goodsUnitMapper.insert(unit);
            }
            return unit;
        }).getId();
    }
}
